﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using GigaSite.Domain.Entities;
using GigaSite.Domain.Enums;
using GigaSite.Domain.Infrastucture.Misc;
using GigaSite.Domain.Interfaces.Repositories;
using GigaSite.Domain.IoC;
using GigaSite.Web.Classes;
using GigaSite.Web.Controllers;
using GigaSite.Web.Models;

namespace GigaSite.Web.Areas.Catalog.Controllers
{
    /// <summary>
    /// Контроллер визиток
    /// </summary>
    public class CardsController : BaseController
    {
        #region Код

        /// <summary>
        /// Выполняем действия при инициализации контроллера
        /// </summary>
        public CardsController(): base()
        {
            
        }

        #endregion

        //
        // GET: /Catalog/Cards/
        #region Категории визиток

        /// <summary>
        /// Страница входа в раздел визитницы
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return RedirectToAction("All");
        }

        /// <summary>
        /// Отображает все визитки в визитнице
        /// </summary>
        /// <returns></returns>
        public ActionResult All()
        {
            // Добавляем корневой элемент цепочки навигаций
            AddNavigationItem("Визитница", Url.Action("Index"));

            // Отдаем вью
            return View();
        }

        /// <summary>
        /// Отображает страницу визиток компаний
        /// </summary>
        /// <param name="id">Идентификатор категории, если его нет то отображается просто список корневых категорий</param>
        /// <returns></returns>
        public ActionResult Companies(long? id)
        {
            // Добавляем корневой элемент цепочки навигаций
            AddNavigationItem("Визитница",Url.Action("Index"));
            
            // Имя вью которое будем отдавать
            string viewName = "CompaniesCategories";
            
            // Репозиторий
            var categoriesRep = Locator.GetService<ICategoriesRepository>();
            AddNavigationItem("Компании", Url.Action("Companies",new {id = new Nullable<int>()}), false);

            if (!id.HasValue)
            {
                // Загружаем родительскую категорию для визиток компаний и выбираем дочерние категории
                var companiesCategory = categoriesRep.Load(CategoryManager.CardsCompaniesCategory); // TODO: remove hardcoding
                ViewBag.categories = companiesCategory.ChildCategories.ToList();
                
                viewName = "CompaniesCategories";
            }
            else
            {
                var companiesCategory = categoriesRep.Load(id.Value);
                ViewBag.childCategories = companiesCategory.ChildCategories.ToList();
                ViewBag.category = companiesCategory;

                // Строим навигационную цепочку
                foreach (var cat in companiesCategory.GetParentCategories().Skip(2))
                {
                    AddNavigationItem(cat.DisplayName,Url.Action("Companies",new {id = cat.Id}));
                }
                AddNavigationItem(companiesCategory.DisplayName,String.Empty,true);

                viewName = "CompaniesCards";
            }

            // Отдаем вид
            return View(viewName: viewName);
        }

        /// <summary>
        /// Отображает страницу визиток специалистов
        /// </summary>
        /// <param name="id">Идентификатор категории, если его нет то отображается просто список корневых категорий</param>
        /// <returns></returns>
        public ActionResult Specialists(long? id)
        {
            // Добавляем корневой элемент цепочки навигаций
            AddNavigationItem("Визитница", Url.Action("Index"));

            // Имя вью которое будем отдавать
            string viewName = "SpecialistsCategories";

            // Репозиторий
            var categoriesRep = Locator.GetService<ICategoriesRepository>();
            AddNavigationItem("Специалисты", Url.Action("Specialists", new { id = new Nullable<int>() }), false);

            if (!id.HasValue)
            {
                // Загружаем родительскую категорию для визиток компаний и выбираем дочерние категории
                var companiesCategory = categoriesRep.Load(CategoryManager.CardsSpecialistsCategory); // TODO: remove hardcoding
                ViewBag.categories = companiesCategory.ChildCategories.ToList();

                viewName = "SpecialistsCategories";
            }
            else
            {
                var companiesCategory = categoriesRep.Load(id.Value);
                ViewBag.childCategories = companiesCategory.ChildCategories.ToList();
                ViewBag.category = companiesCategory;

                // Строим навигационную цепочку
                foreach (var cat in companiesCategory.GetParentCategories().Skip(2))
                {
                    AddNavigationItem(cat.DisplayName, Url.Action("Specialists", new { id = cat.Id }));
                }
                AddNavigationItem(companiesCategory.DisplayName, String.Empty, true);

                viewName = "SpecialistsCards";
            }

            // Отдаем вид
            return View(viewName: viewName);
        }

        /// <summary>
        /// Отображает страницу самых популярных визиток
        /// </summary>
        /// <returns></returns>
        public ActionResult Popular()
        {
            // Добавляем корневой элемент цепочки навигаций
            AddNavigationItem("Визитница", Url.Action("Index"));

            // Добавляем элемент популярных визиток
            AddNavigationItem("Самые популярные визитки",Url.Action("Popular"),true);

            //
            return View();
        }

        #endregion

        #region Просмотр визиток

        /// <summary>
        /// Формирует вью визиток согласно указанным параметрам с с использованием пагинатора
        /// </summary>
        /// <param name="filter">Тип фильтра</param>
        /// <param name="categoryId">Идентификатор категории</param>
        /// <param name="page">Номер страницы</param>
        /// <param name="itemsPerPage">Количество элементов на страницу</param>
        /// <param name="textFilter">Строковый фильтр</param>
        /// <returns></returns>
        public ActionResult CardsView(string filter = "all", long categoryId = -1, int page = 0, int itemsPerPage = 12, string textFilter = "")
        {
            // Репозитории
            var cardsRep = Locator.GetService<IBusinessCardsRepository>();
            var categoriesRep = Locator.GetService<ICategoriesRepository>();

            // Набор визиток
            IEnumerable<BusinessCard> dbCards = Enumerable.Empty<BusinessCard>();
            Category category = null;

            // На основании присланных данных выбираем 
            if (categoryId != -1)
            {
                // Если нам прислана категория - то фильтруем по ней
                category = categoriesRep.Load(categoryId);
                dbCards = category.BusinessCardToCategoryMappings.Select(m => m.BusinessCard);
            }
            else
            {
                // Загружаем все визитки
                dbCards = cardsRep.FindAll();
            }

            // Фильтруем на основании предварительных фильтров
            switch(filter)
            {
                case "company":
                    dbCards = dbCards.Where(c => c.HolderType == BusinessCardHolderTypes.Company);
                    break;
                case "specialist":
                    dbCards = dbCards.Where(c => c.HolderType == BusinessCardHolderTypes.Personal);
                    break;
                default:
                    break;
            }

            // Фильтруем по строке если прислали
            if (!String.IsNullOrEmpty(textFilter) && textFilter.Length > 0)
            {
                dbCards = dbCards.Where(c => c.Title.Contains(textFilter));
            }

            // Отдаем во вью данные
            ViewBag.page = page;
            ViewBag.filter = filter;
            ViewBag.itemsPerPage = itemsPerPage;
            ViewBag.textFilter = textFilter;
            ViewBag.category = category;
            ViewBag.categoryId = categoryId;
            ViewBag.cardsCount = dbCards.Count();

            // Отдаем вью
            return PartialView("CardsView");
        }

        /// <summary>
        /// Отдает вью исключительно из визиток
        /// </summary>
        /// <param name="filter">Тип фильтра</param>
        /// <param name="categoryId">Идентификатор категории</param>
        /// <param name="page">Страница</param>
        /// <param name="itemsPerPage">Количество элементов на странице</param>
        /// <param name="textFilter">Текстовый фильтр</param>
        /// <returns>Партиал вью с карточками</returns>
        public ActionResult GetCards(string filter = "all", long categoryId = -1, int page = 0, int itemsPerPage = 12, string textFilter = "")
        {
            // Репозитории
            var cardsRep = Locator.GetService<IBusinessCardsRepository>();
            var categoriesRep = Locator.GetService<ICategoriesRepository>();

            // Дополнительные флаг
            bool needToSort = true;

            // Набор визиток
            IEnumerable<BusinessCard> dbCards = Enumerable.Empty<BusinessCard>();
            Category category = null;

            // На основании присланных данных выбираем 
            if (categoryId != -1)
            {
                // Если нам прислана категория - то фильтруем по ней
                category = categoriesRep.Load(categoryId);
                dbCards = category.BusinessCardToCategoryMappings.Select(m => m.BusinessCard);
            }
            else
            {
                // Загружаем все визитки
                dbCards = cardsRep.FindAll();
            }

            // Фильтруем на основании предварительных фильтров
            switch (filter)
            {
                case "company":
                    dbCards = dbCards.Where(c => c.HolderType == BusinessCardHolderTypes.Company);
                    break;
                case "specialist":
                    dbCards = dbCards.Where(c => c.HolderType == BusinessCardHolderTypes.Personal);
                    break;
                case "popular":
                    dbCards = dbCards.OrderByDescending(c => c.BusinessCardToUserMappings.Count).ThenBy(c => c.Title);
                    needToSort = false;
                    break;
                default:
                    break;
            }

            // Фильтруем по строке если прислали
            if (!String.IsNullOrEmpty(textFilter) && textFilter.Length > 0)
            {
                dbCards = dbCards.Where(c => c.Title.Contains(textFilter));
            }

            // Пейджионируем
            dbCards = dbCards.Skip(page * itemsPerPage).Take(itemsPerPage);

            // Сортируем если надо
            if (needToSort)
                dbCards = dbCards.OrderBy(c => c.Title);

            // Преобразуем в модели
            var cards = dbCards.Select(c => new BusinessCardModel(c));

            // Отдаем во вью
            return View(cards);
        }

        #endregion

        #region Загрузка визитки

        /// <summary>
        /// Отображает форму загрузки собственной визитки
        /// </summary>
        /// <returns>Форма</returns>
        public ActionResult UploadCard()
        {
            // Проверяем загружена ли у пользователя визитка
            if (CurrentUser == null)
            {
                // Пользователь не авторизован, отправляем его на страницу авторизации
                return RedirectToAction("LogOn", "Account");
            }
            // Получаем пользовательскую визитку
            var imagesRepository = Locator.GetService<IImagesRepository>();
            var cardsRepository = Locator.GetService<IBusinessCardsRepository>();
            UploadBusinessCardModel model = new UploadBusinessCardModel();
            var card =
                CurrentUser.BusinessCardToUserMappings.Where(
                    m => m.User == CurrentUser && m.MappingType == BusinessCardMappingTypes.Owner).Select(
                        m => m.BusinessCard).FirstOrDefault();
            if (card != null)
            {
                model.Id = card.Id;
                model.Title = card.Title;
                model.Description = card.Description;
                model.HolderType = card.HolderType;
                model.ImageURL = imagesRepository.GetFullImageURL(card.ImageURI);
                model.Status = card.Status;
            }

            // получаем количество визиток
            ViewBag.totalCards = cardsRepository.FindAll().Count(c => c.Status == BusinessCardStatuses.Active);

            return View(model);
        }

        /// <summary>
        /// Обрабатывает загрузку пользовательской визитки в систему
        /// </summary>
        /// <param name="model">Модель с данными</param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult UploadCard(UploadBusinessCardModel model)
        {
            // Репозитории
            var cardsRepository = Locator.GetService<IBusinessCardsRepository>();
            var imagesRepository = Locator.GetService<IImagesRepository>();
            var categoriesRepository = Locator.GetService<ICategoriesRepository>();

            // Настройки загрузки визиток
            var premoderation = Global.Settings.Value.GetValue("businessCardsPremodation", false);

            // Загружаем категорию в которую хотя добавить указанную визитку
            var category = categoriesRepository.Load(model.Category);

            // получаем количество визиток
            ViewBag.totalCards = cardsRepository.FindAll().Count(c => c.Status == BusinessCardStatuses.Active);

            // Проверяем прислал ли нам файл
            bool fileSubmitted = false;
            string uploadedFileUri = string.Empty;
            var uploadedFile = Request.Files["CardImage"];
            fileSubmitted = (uploadedFile != null && uploadedFile.ContentLength > 0);

            // Если файл прислан - созраняем его в системе
            if (fileSubmitted)
            {
                var image = imagesRepository.SavePostedFile(uploadedFile);
                uploadedFileUri = image.URI;
            }

            // Выполняем разные действия в зависимости от того что у нас происходит - создание или редактирование визитки
            if (model.Id > 0)
            {
                // Идет редактирование загруженной визитки
                var businessCard = cardsRepository.Load(model.Id);
                if (businessCard == null)
                {
                    throw new ObjectNotFoundException(string.Format("Визитка с идентификатором {0} не найдена", model.Id));
                }

                // Визитка отправляется на проверку модератору
                businessCard.Status = premoderation ? BusinessCardStatuses.Checking : BusinessCardStatuses.Active; // TODO: на боевом режиме изменить
                businessCard.Title = model.Title;
                businessCard.Description = model.Description;
                businessCard.HolderType = model.HolderType;
                businessCard.DateModified = DateTime.Now;
                businessCard.Email = model.Email;
                businessCard.WebSite = model.WebSite;
                businessCard.Phones = model.Phone;
                if (fileSubmitted)
                {
                    businessCard.ImageURI = uploadedFileUri;
                }

                // Изменяем маппинг визитки на категорию
                var mapping = businessCard.BusinessCardToCategoryMappings.FirstOrDefault();
                if (mapping != null)
                {
                    if (mapping.Category.Id != category.Id)
                    {
                        mapping.Category = category;
                        mapping.DateModified = DateTime.Now;
                    }
                }
                else
                {
                    cardsRepository.AddBusinessCardToCategory(businessCard, category);
                }
            }
            else
            {
                // Проверяем собственно прислан ли нам файл визитки
                if (!fileSubmitted)
                {
                    ModelState.AddModelError("CardImage", "Необходимо загрузить файл с изображением визитки");
                    return View(model);
                }

                // Создаем новую визитку в системе
                var newCard = new BusinessCard()
                {
                    CardType = BusinessCardTypes.Uploaded,
                    CityId = 1,
                    // TODO: пока только Хабаровск
                    DateCreated = DateTime.Now,
                    Description = model.Description,
                    Email = model.Email,
                    Title = model.Title,
                    Phones = model.Phone,
                    Status = premoderation ? BusinessCardStatuses.Checking : BusinessCardStatuses.Active, // TODO: на боевом режиме изменить
                    WebSite = model.WebSite,
                    HolderType = model.HolderType,
                    ImageURI = uploadedFileUri
                };
                cardsRepository.Add(newCard);
                cardsRepository.AddBusinessCardToUser(CurrentUser, newCard, BusinessCardMappingTypes.Owner);

                // Добавляем визитку в указанную категорию
                cardsRepository.AddBusinessCardToCategory(newCard, category);
            }

            // Сохраняем изменения
            cardsRepository.SubmitChanges();

            // Переводим пользователя на страницу успешной регистрации визитки
            return View("CardUploaded", model);
        }

        /// <summary>
        /// Отдает контрол с выбором категории в которой находится визитка
        /// </summary>
        /// <returns></returns>
        public ActionResult UploadCardCategoriesControl(string type, long id)
        {
            // репозиторий
            var cardRepository = Locator.GetService<IBusinessCardsRepository>();
            var categoriesRepository = Locator.GetService<ICategoriesRepository>();

            // Загружаем визитку
            var card = cardRepository.Load(id);

            // Загружаем категорию от которой начинаем плясать
            Category parentCategory = type == "personal" ? categoriesRepository.Load(13) : categoriesRepository.Load(12);
            IList<Category> allCategories = new List<Category>();
            parentCategory.GetAllChildCategories(ref allCategories);

            // Формируем список который будем отдавать
            var items = allCategories.Select(category => new SelectListItem()
            {
                Selected =
                    card != null &&
                    card.BusinessCardToCategoryMappings.Any(
                        m => m.CategoryId == category.Id),
                Text = String.Format("{0} {1}", StringUtils.GenerateString('-', category.GetParentCategories().Count()), category.DisplayName),
                Value = category.Id.ToString(),
            }).ToList();
            return PartialView("UploadCardCategoriesControl", items);
        }

        #endregion
    }
}
